home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / System / Sample JGNE⁄cdev 1.2.1 / (MyJGNE.π) / MyJGNE.c < prev    next >
Encoding:
Text File  |  1994-09-29  |  20.4 KB  |  602 lines  |  [TEXT/KAHL]

  1. /*
  2.     MyJGNE.c
  3.     
  4.     Written by Ken Worley, 06/27/94, using Symantec Think C 7.0 (TPM 6.0.1).
  5.     Copyright 1994. All Rights Reserved.
  6.     AOL KNEworley
  7.     internet KNEworley@aol.com
  8.     
  9.     Feel free to use this code in a project of your own, but give me proper
  10.     credit in your documentation or about box.  Feel free to distribute this
  11.     code in its entirety to anyone, but never do so without the copyright
  12.     notice above nor without its accompanying files.  This code is NOT in
  13.     the public domain.  Use of this code in a commercial product requires
  14.     my permission.  I am not responsible for anything that might happen to
  15.     your Mac or your data as a result of using this code.  I believe this
  16.     code is stable and will not cause any damage to anything, but use it
  17.     at your own risk.
  18.         
  19.     This code incorporates 'ShowIconFamily' by Patrick C. Beard and
  20.     modified by James W. Walker.  This piece of code
  21.     is called to display the extension's icon at startup.  This
  22.     code was based on the original ShowInit by Paul Mercer, Darin Adler, Paul
  23.     Snively and Steve Capps.  These are the guys to blame for our startup icon
  24.     parades.  That piece of code (ShowIconFamily.c) is PUBLIC DOMAIN.  I made
  25.     some modifications to it in order to use it without any global variables.
  26.     
  27.     This file includes the main routine which installs the filter (the main
  28.     routine runs at system startup), and the MyTask routine which is the
  29.     calling point of the filter routine.  Any other routines included in
  30.     this file are called by MyTask.
  31.     
  32.     This code sets a couple of the fields in the global data which are
  33.     accessed and/or modified by other code later on.  The 'CPon' field is set to
  34.     true or false depending on whether or not the preferences resource indicates
  35.     the control panel was set to 'on' or 'off' when last closed.  The
  36.     'taskInstalled' field is true if the task was installed, false otherwise.
  37.     
  38.     The following #defines are used to identify icons that are displayed when
  39.     the extension is run:
  40.     
  41.         kIconFamilyID is the resource number of the icon family our final file will
  42.             be using.  The number is used to send to ShowInit so our icon can be
  43.             shown in the startup icon parade.
  44.         
  45.         kXIconID is the resource number of the icon family to be used when there was
  46.             a problem when loading the extension.  This icon looks Xed out.
  47.         
  48.         kNoActionIconID is the resource number of the icon family to be used when
  49.             the patch is not loaded (when the control panel is set to "off").
  50.     
  51.     SO WHAT'S A JGNE?
  52.     
  53.         The Mac System recognizes a low memory global with the name JGNEFilter.
  54.         This global CAN point to a routine used to "filter" ALL events that are
  55.         retrieved by calling GetNextEvent or WaitNextEvent.  Without any
  56.         modification, this global is normally NULL.  We can, however, fill it
  57.         with the address of a "filter procedure" that examines an event and
  58.         decides whether or not the application gathering it should actually receive
  59.         it or not (and possibly doing some other things along the way).  I also
  60.         refer to this filter procedure as the "task code."
  61.         
  62.     MEMORY SHARING
  63.     
  64.         The JGNE installer code (the main routine) shares memory with the control
  65.         panel code by storing the address of a global structure (myData) in a
  66.         resource.  The cdev accesses the resource and checks a constant field to
  67.         ensure that it has the shared data.
  68.         
  69.         The installer code (and consequently its globals) hangs around even after it
  70.         runs by retrieving a handle to itself, locking itself down, and telling the
  71.         resource manager to forget it.  Since we also include the JGNE filter task
  72.         code in this file, the installer code and the task code are all saved in
  73.         the same chunk of memory along with the globals.  That's why the task code
  74.         can access the same globals as the installer code.
  75.     
  76.     SETUPA4
  77.     
  78.         The THINK C compiler has a nice mechanism that allows global variables in
  79.         code resources.  Normally, global variables in applications are accessed
  80.         through the A5 register.  Since code resources run while an application
  81.         is using the A5 register, THINK lets the code resource use the A4 register
  82.         to access its globals.  The mechanism allows access to the same globals
  83.         by any routine in the same file (compiled into the same resource).  See
  84.         THINK's documentation for further explanation.
  85.         
  86.     WHY IS THE CONTROL PANEL IN A DIFFERENT PROJECT?
  87.     
  88.         The system requires that a control panel reside in its own resource with
  89.         a certain resource type and a certain resource number.  This code is saved
  90.         in a code resource of type 'INIT' with resource id 0.  Code resources of
  91.         type 'INIT' in a file of type 'INIT' that are in the System Folder,
  92.         Extensions Folder, or Control Panels Folder are automatically executed at
  93.         startup time.  This INIT file is also allowed to have a code resource of
  94.         type 'cdev' in it allowing us to combine a control panel (cdev) and
  95.         extension (INIT) into the same finished file.  They only have to be compiled
  96.         separately and put into different code resources.
  97.     
  98.     WHAT IF TWO EXTENSIONS BOTH WANT TO INSTALL JGNE FILTERS?
  99.     
  100.         Any decent JGNE filter saves the address of any filter already installed
  101.         and jumps to that filter after it runs itself.  Like so...
  102.         
  103.             JGNEFilter --> aFilter        (global already points to a filter)
  104.             oldFilter=JGNEFilter        (we save the value in a global of our own)
  105.             JGNEFilter=myFilter            (and install our own filter)
  106.             
  107.             myFilter-->oldFilter        (after myFilter runs, it jumps to the)
  108.                                         (address stored in oldFilter)
  109.         
  110.         A long chain of JGNE filters might exist, each calling the next filter
  111.         in line until execution is returned to the program that called GetNextEvent
  112.         or WaitNextEvent in the first place.
  113.     
  114.     THE 'sysz' RESOURCE
  115.     
  116.         There is a resource included in the project of type 'sysz.'  This resource
  117.         holds one long value that, ONLY in PRE system 7 machines, acts as a request
  118.         to add that number of bytes to the system heap.  Again, this only has any
  119.         effect if loaded on a system 6 or earlier machine.  The number of bytes
  120.         requested is added to the system heap, but are NOT reserved for any code
  121.         or program in particular.
  122.         
  123.     NOTE
  124.     
  125.         You should not need to make any changes to anything in this file.
  126.         Any allocation of memory or loading of resources should be done in
  127.         MyInitialize.c.  The only other routine you should need to modify is
  128.         the MyEvtHandler routine in the file MyEvtHandler.c.
  129. */
  130.  
  131. /********************* INCLUDED HEADERS ***********************/
  132.  
  133. #include <SetUpA4.h>    /* This header file contains code!!  Since            */
  134.                         /* I'm using the standard THINK C header which        */
  135.                         /* automatically jumps to main, I'm all right        */
  136.                         /* including this here.  Using the standard header    */
  137.                         /* is an option in the project type dialog.            */
  138.                         /* The standard header is used when the Custom        */
  139.                         /* header check box is NOT checked.                    */
  140.  
  141. #include "SharedData.h"    /* includes definitions of data structures            */
  142.                         /* used both here and in the cdev, and some            */
  143.                         /* common defines used by both.                        */
  144.  
  145. /*********** PROJECT SPECIFIC DEFINES, GLOBALS, ETC. *************/
  146.  
  147. #include "MyDefines&Globals.h"
  148.  
  149. /************************** DEFINES ******************************/
  150.  
  151. /* The following three icons are the ones I defined for this example.  Modify them */
  152. /* for your purposes or come up with some on your own.  The numbers */
  153. /* are resource numbers. */
  154.  
  155. #define        kIconFamilyID        -4064    /* ICN# rsrc with our icons */
  156. #define        kXIconID            -4033    /* Xed out icon family */
  157. #define        kNoActionIconID        -4034    /* icon family when we're OFF */
  158.  
  159. #define        kProcessNullEvts    false    /* examine/process null events? */
  160.  
  161. /************************** MACROS ******************************/
  162.  
  163. #define        GoodEvt(x)    (x & 0xFF00)    /* test high byte only */
  164.  
  165. /************************* GLOBALS ****************************/
  166.  
  167. Ptr        JGNEfilter : 0x29A;    /* low memory global that points to the */
  168.                             /* GetNextEvent filter routine */
  169.  
  170. /* Memory that the control panel needs to access also */
  171.  
  172. myDataStruct    myData;
  173.  
  174. /* Whatever other globals we need */
  175.  
  176. pascal void    (*theNextFilter)( void );    /* the next JGNE filter (if any) */
  177.  
  178. Boolean            interceptIt;    /* are we intercepting the event? */
  179. short*            myReturnVal;    /* addr of filter's return value on stack */
  180. EventRecord*    myEvtPtr;        /* pointer to the event record */
  181. short            stillHasEvt;    /* do we have an event to work with? */
  182.  
  183. /************************ PROTOTYPES **************************/
  184.  
  185. void        main( void );
  186.  
  187. Boolean        MyInitialize( myDataPtr myData, Boolean *installTask, Boolean *showIcon );
  188.  
  189. void        ShowIconFamily( short iconId );
  190.  
  191. pascal void        MyTask( void );
  192.  
  193. Boolean        ProcessEvt( EventRecord *event );
  194.  
  195. #include "MyEvtHandler.h"    /* prototypes/defines for routines in MyEvtHandler.c */
  196.  
  197. /************************ FUNCTIONS ***************************/
  198.  
  199. /* main */
  200. // This routine is actually the extension or INIT code that is run at startup time.
  201. // Its job is to initialize variables, allocate any memory we'll need later (in the
  202. // filter code), check the preferences resource, and install the filter code.
  203.  
  204. void    main( void )
  205. {
  206.     Boolean                showStartupIcon;    /* show icon at startup? */
  207.     Boolean                installTask;        /* install the task? */
  208.     
  209.     Boolean                stillOK;            /* still OK to proceed? */
  210.     
  211.     Handle                me;                    /* a handle to this code */
  212.     
  213.     /* Set up for A4 based global variables (specific to THINK C) */
  214.     
  215.         RememberA0();    /* A0 contains the base address of this code */
  216.         SetUpA4();
  217.  
  218.     /* Initialize some local variables */
  219.     
  220.         stillOK = true;
  221.         showStartupIcon = true;
  222.         installTask = true;
  223.     
  224.     /* Retrieve a handle to this code and lock it down */
  225.         
  226.         {
  227.             Ptr        ptrToMe;
  228.             
  229.             /* Move the value in register A0 to ptrToMe.  A0 holds the */
  230.             /* direct address of this code (courtesy THINK). */
  231.             
  232.                 asm
  233.                 {
  234.                     MOVE.L    A0,ptrToMe
  235.                 }
  236.             
  237.             /* Now recover the Handle to this code using RecoverHandle */
  238.             
  239.                 me = RecoverHandle( ptrToMe );
  240.             
  241.             /* Make the Resource Manager forget about us and lock this */
  242.             /* code down so it stays in memory even after the extension */
  243.             /* has run its course.  This allows the globals we've defined */
  244.             /* to hang around (as well as the task code). */
  245.             
  246.                 DetachResource( me );
  247.                 HLock( me );
  248.         }
  249.         
  250.     /* Initialize some values */
  251.  
  252.         if ( stillOK )
  253.         {
  254.             /* This check value is checked by the cdev to make sure the */
  255.             /* extension was run at system startup time. */
  256.             
  257.                 myData.checkValue = 0x12341234;
  258.             
  259.             /* Set INITrun flag so control panel will know we've run */
  260.             
  261.                 myData.INITrun = true;
  262.         }
  263.         
  264.     // Call MyInitialize to initialize variables, allocate memory, load resources,
  265.     // etc.  MyInitialize returns a Boolean value put into stillOK to indicate
  266.     // if all is well, and may also modify the values in installTask and
  267.     // showStartupIcon to affect whether or not the filter code is actually
  268.     // installed and whether or not the startup icon is shown.
  269.     
  270.         if ( stillOK )
  271.             stillOK = MyInitialize( &myData, &installTask, &showStartupIcon );
  272.         
  273.     /*    Store the address of myData in a resource that can be accessed by
  274.      *    our control panel.  That way, the control panel can use and change
  275.      *    that data.
  276.      */
  277.         if ( stillOK )
  278.         {
  279.             memAddrHdl            theMemAddr;        /* resource used to hold the */
  280.                                                 /* addr of the data structure */
  281.                                                 /* shared with the cdev */
  282.     
  283.             // load the existing resource so we can change it
  284.             
  285.             theMemAddr = (memAddrHdl)Get1Resource( kMemAddrType, kMemAddrID );
  286.             if ( theMemAddr )    /* got the resource */
  287.             {
  288.                 (*theMemAddr)->theAddr = (long)(&myData); /* addr of myData */
  289.                 ChangedResource( (Handle)theMemAddr );
  290.                 WriteResource( (Handle)theMemAddr );    /* write rsrc back to file */
  291.             }
  292.             else    // resource not found, so create a new resource
  293.             {
  294.                 theMemAddr = (memAddrHdl)NewHandleSysClear( sizeof( long ) );
  295.                 if ( theMemAddr )
  296.                 {
  297.                     (*theMemAddr)->theAddr = (long)(&myData); /* addr of myData */
  298.                     AddResource( (Handle)theMemAddr, kMemAddrType, kMemAddrID,
  299.                         "\pShared Memory Addr" );        /* add a rsrc to file */
  300.                     WriteResource( (Handle)theMemAddr ); /* write it out to the file */
  301.                 }
  302.                 else
  303.                     stillOK = false;    /* unable to allocate memory for new rsrc */
  304.             }
  305.         }
  306.  
  307.     /*    Store the address of the next JGNE filter for the task code to
  308.      *    jump to later (after it does its own processing).
  309.      */
  310.      
  311.          theNextFilter = (void*)JGNEfilter;    /* save old filter address */
  312.          
  313.     /*    Now we actually install the filter. */
  314.     
  315.         if ( stillOK && installTask )
  316.         {
  317.             JGNEfilter = (void*)MyTask;
  318.  
  319.             myData.taskInstalled = true;
  320.         }
  321.         else
  322.         {
  323.             myData.taskInstalled = false;
  324.         }
  325.     
  326.     /*    Show our icon in the startup icon parade.  If there was a problem somewhere
  327.      *    along the way, we'll show the icon even if the control panel says not to.
  328.      */
  329.  
  330.         if ( showStartupIcon || ( !stillOK ) )
  331.         {
  332.             if ( stillOK )
  333.                 if ( installTask )
  334.                     ShowIconFamily( kIconFamilyID );
  335.                 else
  336.                     ShowIconFamily( kNoActionIconID );
  337.             else
  338.                 ShowIconFamily( kXIconID );
  339.         }
  340.     
  341.     /* If not still OK now, unlock this code and make it purgeable so it doesn't */
  342.     /* continue to take up valuable space in the system heap. */
  343.     
  344.         if ( !stillOK )
  345.         {
  346.             HUnlock( me );
  347.             HPurge( me );
  348.         }
  349.         
  350.     /* Restore old A4 value */
  351.     
  352.         RestoreA4();
  353. }
  354.  
  355. #include "MyInitialize.c"
  356.  
  357. /* myTask */
  358. //
  359. // This is the "filter" or "task" code that gets called every time an event is
  360. // returned to an application.  This routine is mainly "glue" code that extracts
  361. // the information we need from the stack and registers, calls other filters that
  362. // are installed, and saves the registers.  Most of our actual work is done
  363. // elsewhere in the ProcessEvt routine.
  364.  
  365. pascal void MyTask( void )
  366. {
  367.     // At this point:
  368.     //        -> no stack frame (LINK) is generated because there are no local vars
  369.     //        -> there is a return value (short, 2 bytes) on the stack that tells
  370.     //            the system if it should accept the event (nonzero yes/zero no).
  371.     //            The routine is declared with a void return value because we're
  372.     //            going to set the return value manually when we return.
  373.     //        -> on top of the return value is the return address (4 bytes).  This
  374.     //            is the "top" of the stack right now.
  375.     //        -> on entry, register A1 points to the event record
  376.     //        -> register D0 contains the "return value" that tells us whether
  377.     //            or not we actually have an event. This is indicated by the
  378.     //            high byte of the low word of that register.
  379.     //
  380.     //        | prev stack contents        |
  381.     //        |---------------------------|
  382.     //        | short ret value 2 bytes    |
  383.     //        |---------------------------|
  384.     //        | return address            |
  385.     //        |        4 bytes                |
  386.     //        |---------------------------|    <- stack pointer (SP)
  387.     //
  388.     
  389.     asm
  390.     {
  391.         MOVEM.L    A0-A6/D1-D7,-(SP)        ;SAVE REGISTERS
  392.         MOVE.L    SP,A2                    ;COPY STACK PTR TO REG A2
  393.         ADD.L    #60,A2                    ;ADD 60 TO A2 TO GET ADDR OF RETURN
  394.                                         ;VALUE ON THE STACK
  395.         MOVE.L    A1,A3                    ;COPY REG A1 TO REG A3
  396.     }
  397.  
  398.     //        | prev stack contents        |
  399.     //        |---------------------------|
  400.     //        | short ret value 2 bytes    |    A1 -> Event Record
  401.     //        |---------------------------|    A3 -> Event Record
  402.     //        | return address            |
  403.     //        |        4 bytes                |    A2 -> Return value
  404.     //        |---------------------------|
  405.     //        |                             |
  406.     //        | saved registers            |
  407.     //        |         56 bytes            |
  408.     //        |         4 bytes per            |
  409.     //        |         register saved        |
  410.     //        |                             |
  411.     //        |---------------------------|    <- stack pointer (SP)
  412.     //
  413.     
  414.     // Set up for access to global variables through register A4.
  415.     // This process uses register A1 and sets register A4 to point
  416.     // to our global variables area.
  417.     
  418.         SetUpA4();
  419.     
  420.     asm
  421.     {
  422.         MOVE.L    A3,A1                    ;RESTORE REG A1 FROM REG A3 SO IT
  423.                                         ;AGAIN POINTS TO EVENT RECORD
  424.         MOVE.L    A1,myEvtPtr                ;PUT EVENT PTR INTO GLOBAL myEvtPtr
  425.         MOVE.L    A2,myReturnVal            ;STORE ADDR OF RETURN VALUE IN THE
  426.                                         ;GLOBAL myReturnVal
  427.     }
  428.  
  429.     //        | prev stack contents        |
  430.     //        |---------------------------|
  431.     //        | short ret value 2 bytes    |    A1 -> Event Record
  432.     //        |---------------------------|    A3 -> Event Record
  433.     //        | return address            |
  434.     //        |        4 bytes                |    A2 -> Return value
  435.     //        |---------------------------|
  436.     //        |                             |
  437.     //        | saved registers            |
  438.     //        |         56 bytes            |    myEvtPtr -> Event Record
  439.     //        |         4 bytes per            |    myReturnVal -> Return value
  440.     //        |         register saved        |
  441.     //        |                             |
  442.     //        |---------------------------|
  443.     //        | old reg A4 value            |
  444.     //        |         4 bytes                |
  445.     //        |---------------------------|    <- stack pointer (SP)
  446.     //
  447.     
  448.     // When we initially installed this routine as a filter (in the INIT), we
  449.     // checked to see if one or more filters was already installed.  If there
  450.     // was, the address of the next filter is stored in the global theNextFilter.
  451.     //
  452.     // If there is a next filter, call it now.
  453.     //
  454.     // It is the high byte of the value in D0 that is important.
  455.     
  456.         asm
  457.         {
  458.             MOVE.W    D0,stillHasEvt        ;move D0 to global stillHasEvt
  459.         }
  460.         
  461.         if ( theNextFilter )
  462.         {
  463.             asm
  464.             {
  465.                 MOVE.W    stillHasEvt,D0        ;make sure D0 holds the correct value
  466.                 MOVE.W    stillHasEvt,-(SP)    ;also copy the value to the top of
  467.                                             ;the stack
  468.             }
  469.             
  470.             (*theNextFilter)();
  471.             
  472.             asm
  473.             {
  474.                 MOVE.W    (SP)+,stillHasEvt        ;get the new return value and
  475.                 MOVE.L    myReturnVal,A0            ;copy it to where the old return
  476.                 MOVE.W    stillHasEvt,(A0)        ;value was on the stack
  477.             }
  478.         }
  479.     
  480.     // At this point, stillHasEvt represents either the same return value we
  481.     // initially had when we started, or the return value from the next filter
  482.     // if one was called.
  483.     //
  484.     // If we are still working with a valid event then we'll
  485.     // now process the event ourselves and decide if we want to intercept it.
  486.     
  487.         if ( GoodEvt(stillHasEvt) || kProcessNullEvts )
  488.             interceptIt = ProcessEvt( myEvtPtr );
  489.         else
  490.             interceptIt = false;
  491.     
  492.     // After the next filter was called, the return value on the stack was
  493.     // changed to reflect the new result.  We'll only need to change that
  494.     // result now if we're going to intercept the event.  We do that by
  495.     // making the return value ZERO.
  496.     
  497.         if ( interceptIt )
  498.         {
  499.             myEvtPtr->what = nullEvent;
  500.             (*myReturnVal) = 0;
  501.         }
  502.     
  503.     // Copy the return value to register D0.  D0 and the return value on
  504.     // the stack should mirror each other when we exit.
  505.     
  506.         asm
  507.         {
  508.             MOVE.L    myReturnVal,A2        ;get return value addr on stack
  509.             CLR.L    D0                    ;clear out register D0 first
  510.             MOVE.W    (A2),D0                ;copy the return value to D0
  511.         }
  512.         
  513.     // Now restore the previous value of the A4 register.  We'll no longer
  514.     // have access to our globals.
  515.     
  516.         RestoreA4();
  517.  
  518.     //        | prev stack contents        |
  519.     //        |---------------------------|
  520.     //        | short ret value 2 bytes    |
  521.     //        |---------------------------|
  522.     //        | return address            |
  523.     //        |        4 bytes                |
  524.     //        |---------------------------|
  525.     //        |                             |
  526.     //        | saved registers            |
  527.     //        |         56 bytes            |
  528.     //        |         4 bytes per            |
  529.     //        |         register saved        |
  530.     //        |                             |
  531.     //        |---------------------------|    <- stack pointer (SP)
  532.     //
  533.     
  534.     asm
  535.     {
  536.         MOVEM.L        (SP)+, A0-A6/D1-D7        ;RESTORE SAVED REGISTERS
  537.     }
  538.  
  539.     //        | prev stack contents        |
  540.     //        |---------------------------|
  541.     //        | short ret value 2 bytes    |
  542.     //        |---------------------------|
  543.     //        | return address            |
  544.     //        |        4 bytes                |
  545.     //        |---------------------------|    <- stack pointer (SP)
  546.     //
  547.     // At the end of this routine, the compiler automatically inserts an RTS
  548.     // command which takes the return address off the stack and jumps to it
  549.     // leaving only the return value on the stack (plus the previous contents).
  550. }
  551.  
  552.  
  553. /*    The ProcessEvt routine:
  554.  *        • checks the control panel to see if it is "on"
  555.  *        • calls MyEvtHandler to process the event and see if it should be
  556.  *            intercepted.
  557.  *        • if the event is to be intercepted, ProcessEvt returns true.
  558.  *            Otherwise, it returns false.
  559.  */
  560. Boolean ProcessEvt( EventRecord *event )
  561. {
  562.     Boolean            intercept;
  563.                                     
  564.     /*    If the control panel setting is not ON, we take no further action.
  565.      *    CPon was set initially by the extension based on a value in the
  566.      *    preferences resource.  It may later have been modified by the on/off
  567.      *    setting in the control panel.
  568.      *
  569.      *    Here, we process the event and check to see if it will be
  570.      *    intercepted by calling the MyEvtHandler routine.  Our return value is based
  571.      *    on the return value of MyEvtHandler.
  572.      */
  573.     
  574.         if ( myData.CPon )
  575.         {
  576.             long    oldA5;
  577.             
  578.             /* Make sure the A5 register holds the current app's correct */
  579.             /* A5 world value, and save the previous value. */
  580.             
  581.                 oldA5 = SetCurrentA5();
  582.                 
  583.             // Call MyEvtHandler to process the event.  If MyEvtHandler returns
  584.             // true, then we'll return true so that the event is
  585.             // "intercepted."  This causes WNE/GNE to return false (basically
  586.             // a NULL event.  If MyEvtHandler returns false, then we'll also
  587.             // return false and the event is returned to the calling
  588.             // application as a real event.
  589.             
  590.                 intercept = MyEvtHandler( event );
  591.             
  592.             /* Restore the previous A5 value */
  593.             
  594.                 SetA5( oldA5 );
  595.          }
  596.      return intercept;
  597. }
  598.  
  599. #include "ShowIconFamily.c"
  600.  
  601. #include "MyEvtHandler.c"
  602.